/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "GPKMeshLoadImpl.h"

#include "OgreMeshSerializer.h"

#include "NgFileSystem.h"
#include "GPKArchiveManager.h"
#include "GameMaterialManager.h"

#include "GameObject.h"

namespace PQEngine
{
	GPKSkeletonManualLoader::GPKSkeletonManualLoader(std::string path)
		: _path(path)
	{
	}

	GPKSkeletonManualLoader::~GPKSkeletonManualLoader()
	{
	}

	void GPKSkeletonManualLoader::loadResource(Ogre::Resource *resource)
	{
		assert(resource);
		Ogre::Skeleton* skeleton=static_cast<Ogre::Skeleton*>(resource);
		
		GPKFile* file=GNgGPKArchiveManager.getFile(_path);
		if(!file||!file->ok()){
			return;
		}

		file->open();
		int size=file->length();
		char* buf=new char[size];
		file->read(buf,size);
		file->close();

		Ogre::DataStreamPtr stream=Ogre::DataStreamPtr(new Ogre::MemoryDataStream(buf,size));
		Ogre::SkeletonSerializer serializer;
		serializer.importSkeleton(stream,skeleton);

	}

	void GPKMeshSerializerListener::processMaterialName(Ogre::Mesh *mesh, Ogre::String *name)
	{
		//load material into ogre,Ogre::SubMesh setMaterialName 
		//and change name will all be override by OgreMeshSerializer
		
		if(!GNgMaterialManager.hasMaterial(*name)){
			//create default material for this
			GNgMaterialManager.createDefaultMaterial(*name);
		}
	}

	void GPKMeshSerializerListener::processSkeletonName(Ogre::Mesh *mesh, Ogre::String *name)
	{
		Ogre::String parentPath=NgFileSystem::getParentPath(_meshPath);
		Ogre::String skeletonName=*name;
		Ogre::String skeletonPath=parentPath+"/";
		skeletonPath+=skeletonName;

		GPKSkeletonManualLoader* loader=new GPKSkeletonManualLoader(skeletonPath);
		Ogre::SkeletonManager::getSingleton().load(skeletonName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,true,loader);

		if(loader){
			delete loader;
		}

	}


	GPKMeshManualLoader::GPKMeshManualLoader(std::string path)
		: _path(path)
	{
	}

	GPKMeshManualLoader::~GPKMeshManualLoader()
	{
	}

	void GPKMeshManualLoader::loadResource(Ogre::Resource *resource)
	{
		assert(resource);
		
		Ogre::Mesh* mesh=static_cast<Ogre::Mesh*>(resource);
		
		GPKFile* file=GNgGPKArchiveManager.getFile(_path);
		if(!file||!file->ok()){
			delete mesh;//right?
			return;
		}

		file->open();
		int size=file->length();
		char* buf=new char[size];
		file->read(buf,size);
		file->close();

		Ogre::DataStreamPtr stream=Ogre::DataStreamPtr(new Ogre::MemoryDataStream(buf,size));

		GPKMeshSerializerListener* listener=new GPKMeshSerializerListener(_path);
		Ogre::MeshSerializer serializer;
		serializer.setListener(listener);
		serializer.importMesh(stream,mesh);

		
		delete listener;
		delete buf;

	}


	std::map<std::string,Ogre::Mesh*> GPKMeshLoadImpl::_loadedMeshes;
	GPKMeshLoadImpl::GPKMeshLoadImpl(SceneObject* sceneObject, std::string path,SceneResourceLocation loc)
		: SceneResourceLoadImpl(sceneObject,path,loc),_ok(false)
	{
		assert(_sceneObject);
	}

	GameObject* GPKMeshLoadImpl::load()
	{
		std::string meshName=_path;//use path as our mesh name(Any better idea for unique mesh name?)
		std::map<std::string,Ogre::Mesh*>::iterator it=_loadedMeshes.find(meshName);

		GPKMeshManualLoader *meshLoader =0;
		if(it!=_loadedMeshes.end()){//find just create gameobject
			GameObject* obj= (GameObject*)_sceneObject->createEntityObject(meshName);
			return obj;
		}

		//load mesh material,because the material script is universal may load before any mesh construct
		//or even process all file with .materal at init progress of the whole system
		GNgMaterialManager.load(_path);//skeleton ?

		//load mesh geometry(load with skeleton?)
		meshLoader= new GPKMeshManualLoader(_path);
		Ogre::Mesh* mesh=_sceneObject->createMesh(meshName,meshLoader);
		_loadedMeshes.insert(std::map<std::string,Ogre::Mesh*>::value_type(meshName,mesh));
		
		GameObject* obj= (GameObject*)_sceneObject->createEntityObject(meshName);

		if(meshLoader){
			delete meshLoader;
		}

		//
		return obj;
	}

}
